package cn.com.idmy.auth.session;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static cn.com.idmy.auth.AuthConfig.NEVER_EXP;
import static cn.com.idmy.auth.AuthConfig.NOT_VALUE_EXP;


public class SessionDaoDefaultImpl<ID> implements SessionDao<Session<ID>> {
    protected Map<String, String> dataMap = new ConcurrentHashMap<>();
    protected Map<String, Long> expMap = new ConcurrentHashMap<>();

    protected static long getExp(long exp) {
        return exp == NEVER_EXP ? NEVER_EXP : System.currentTimeMillis() + exp * 1000;
    }

    protected long getExpByKey(String key) {
        deleteKeyByExp(key);

        Long exp = expMap.get(key);
        if (exp == null) {
            return NOT_VALUE_EXP;
        }
        if (exp == NEVER_EXP) {
            return NEVER_EXP;
        }
        long timeout = (exp - System.currentTimeMillis()) / 1000;
        if (timeout < 0) {
            dataMap.remove(key);
            expMap.remove(key);
            return NOT_VALUE_EXP;
        }
        return timeout;
    }

    /**
     * 1、数据存在。
     * 2、不是 [ 永不过期 ]。
     * 3、已经超过过期时间。
     */
    void deleteKeyByExp(String key) {
        Long expire = expMap.get(key);
        if (expire != null && expire != NEVER_EXP && expire < System.currentTimeMillis()) {
            dataMap.remove(key);
            expMap.remove(key);
        }
    }

    @Override
    @Nullable
    public Session<ID> get(@NotNull String key) {
        deleteKeyByExp(key);
        String json = dataMap.get(key);
        return JSON.parseObject(json, new TypeReference<>() {
        });
    }

    @Override
    public long getExp(@NotNull String key) {
        return getExpByKey(key);
    }

    @Override
    public void getExp(@NotNull String key, long exp) {
        expMap.put(key, getExp(exp));
    }

    @Override
    public void update(@NotNull String key, @NotNull Session<ID> session, long exp) {
        if (exp != 0 && exp > NOT_VALUE_EXP) {
            dataMap.put(key, JSON.toJSONString(session));
            expMap.put(key, getExp(exp));
        }
    }

    @Override
    public void update(@NotNull String key, @NotNull Session<ID> session) {
        if (getExpByKey(key) != NOT_VALUE_EXP) {
            dataMap.put(key, JSON.toJSONString(session));
        }
    }

    @Override
    public void remove(@NotNull String key) {
        dataMap.remove(key);
        expMap.remove(key);
    }
}
